`include "defines.v"

module Forwarding (
    input  wire [ 4: 0] rs1_addr,
    input  wire [ 4: 0] rs2_addr,
    input  wire [11: 0] csr_addr,

    input  wire [ 4: 0] rd_addr_ex,
    input  wire [ 4: 0] rd_addr_mem,
    input  wire [ 4: 0] rd_addr_wb,
    input  wire [11: 0] csr_addr_ex,
    input  wire [11: 0] csr_addr_mem,
    input  wire [11: 0] csr_addr_wb,
    
    input  wire         RegWr_ex,
    input  wire         RegWr_mem,
    input  wire         RegWr_wb,
    input  wire         MemToReg_ex,
    input  wire         MemToReg_mem,
    input  wire         MemToReg_wb,
    input  wire         is_system_inst_ex,
    input  wire         is_system_inst_mem,
    input  wire         is_system_inst_wb,
    output wire         ForwardA,
    output wire         ForwardB,
    output wire         ForwardCSR,

    input  wire [`xlen] rd_data_ex,
    input  wire [`xlen] rd_data_mem,
    input  wire [`xlen] rd_data_wb,
    input  wire [`xlen] csr_data_ex,
    input  wire [`xlen] csr_data_mem,
    input  wire [`xlen] csr_data_wb,
    output wire [`xlen] forward_rs1_data,
    output wire [`xlen] forward_rs2_data,
    output wire [`xlen] forward_csr_data
);
wire forwardA_ex;
wire forwardA_mem;
wire forwardA_wb;
wire forwardB_ex;
wire forwardB_mem;
wire forwardB_wb;
wire forwardCSR_ex;
wire forwardCSR_mem;
wire forwardCSR_wb;

assign forwardA_ex = RegWr_ex && (rd_addr_ex == rs1_addr) && (|rd_addr_ex) && (~MemToReg_ex);
assign forwardB_ex = RegWr_ex && (rd_addr_ex == rs2_addr) && (|rd_addr_ex) && (~MemToReg_ex);
assign forwardCSR_ex = is_system_inst_ex && (csr_addr_ex == csr_addr);

assign forwardA_mem = RegWr_mem && (rd_addr_mem == rs1_addr) && (|rd_addr_mem) && (~MemToReg_mem);
assign forwardB_mem = RegWr_mem && (rd_addr_mem == rs2_addr) && (|rd_addr_mem) && (~MemToReg_mem);
assign forwardCSR_mem = is_system_inst_mem && (csr_addr_mem == csr_addr);

assign forwardA_wb = RegWr_wb && (rd_addr_wb == rs1_addr) && (|rd_addr_wb);
assign forwardB_wb = RegWr_wb && (rd_addr_wb == rs2_addr) && (|rd_addr_wb);
assign forwardCSR_wb = is_system_inst_wb && (csr_addr_wb == csr_addr);

assign ForwardA = forwardA_ex | forwardA_mem | forwardA_wb;
assign ForwardB = forwardB_ex | forwardB_mem | forwardB_wb;
assign ForwardCSR = forwardCSR_ex | forwardCSR_mem | forwardCSR_wb;

//priority mux
assign forward_rs1_data = forwardA_ex  ? rd_data_ex  :
                         forwardA_mem ? rd_data_mem :
                         forwardA_wb  ? rd_data_wb  : 64'h0 ;

assign forward_rs2_data = forwardB_ex  ? rd_data_ex  :
                         forwardB_mem ? rd_data_mem :
                         forwardB_wb  ? rd_data_wb  : 64'h0 ;

 assign forward_csr_data = forwardCSR_ex  ? rd_data_ex  :
                         forwardB_mem ? rd_data_mem :
                         forwardB_wb  ? rd_data_wb  : 64'h0 ;                        
//
                
endmodule